package fr.cephb.joperon.tool.stypesgui;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridLayout;
import java.awt.LinearGradientPaint;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Vector;

import javax.script.Bindings;
import javax.script.Compilable;
import javax.script.CompiledScript;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.table.AbstractTableModel;



import com.sleepycat.db.DatabaseException;
import com.sleepycat.db.OperationStatus;
import com.sleepycat.db.Transaction;

import fr.cephb.berkeley.baseapi.db.PrimaryDB;
import fr.cephb.berkeley.baseapi.db.Walker;
import fr.cephb.joperon.core.types.Fid;
import fr.cephb.joperon.structures.STypes;


/**
 * 
 * Frame
 *
 */
public class Frame
	extends JFrame
	{
	private static final long serialVersionUID = 1L;
	private static final int ORGANISM_ID=1;
	private JPanel drawinArea;
	private volatile BufferedImage offscren=null;
	private DrawingThread runThread=null;
	private volatile boolean dirty_flag=true;
	private Transaction txn=null;
	private JProgressBar progress=null;
	private Point mouseStart;
	private Point mouseCurrent;
	
	private Model model=null;
	private Model.ChromInfo currentChrom=null;
	private int view_start=0;
	private int view_length=0;
	private JTextField txtFieldStart;
	private JTextField txtFieldEnd;
	private JTextField txtFieldLength;
	private SelectorPane selectPanes[];
	private GenotypeTable genotypeTable;
	private Compilable compiler;
	private JComboBox comboChromosome;
	
	/**
	 * 
	 */
	private static class TableRow
		{
		Fid fid;
		STypes reference;
		Genotype genotypes[];
		}
	
	/**
	 * 
	 * GenotypeTable
	 *
	 */
	private class GenotypeTable
		extends AbstractTableModel
		{
		private static final long serialVersionUID = 1L;
		private List<TableRow> rows=new ArrayList<TableRow>();
		GenotypeTable()
			{
			
			}
		@Override
		public int getColumnCount()
			{
			return 5+(Frame.this.model.getNumberOfSamples()-1)/2;
			}
		@Override
		public boolean isCellEditable(int rowIndex, int columnIndex)
			{
			return false;
			}
		@Override
		public String getColumnName(int column)
			{
			switch (column)
				{
				case 0: return "Chrom";
				case 1: return "Position";
				case 2: return "Ref.";
				case 3: return "SNP";
				case 4: return "Repeat";
				default: break;
				}

			return "Genotype["+(column-5)+"]";
			}
		
		@Override
		public Class<?> getColumnClass(int column)
			{
			switch (column)
				{
				case 0: return Integer.class;
				case 1: return Integer.class;
				case 2: return Character.class;
				case 3: return Boolean.class;
				case 4: return Boolean.class;
				}
			return String.class;
			}
		
		@Override
		public int getRowCount()
			{
			return rows.size();
			}
		@Override
		public Object getValueAt(int rowIndex, int columnIndex)
			{
			TableRow row= this.rows.get(rowIndex);
			switch (columnIndex)
				{
				case 0: return row.fid.getChromosomeId();
				case 1: return row.fid.getPosition();
				case 2: return row.reference.getMajorBase();
				case 3: return row.reference.isSnp();
				case 4: return row.reference.isRepeat();
				default: break;
				}
			return row.genotypes[columnIndex-5].toString();
			}
		}
	
	
	/**
	 * 
	 * SelectorPane
	 *
	 */
	private class SelectorPane
		extends JPanel
		implements ActionListener
		{
		private static final long serialVersionUID = 1L;
		private JTextArea area;
		private JCheckBox cboxEnable;
		private JTextField info;
		private JButton colorButton;
		Color color;
		SelectorPane()
			{
			super(new BorderLayout(5,5));
			
			float gray=(float)Math.random();
			color=new Color(gray, gray, gray);
			setBorder(new LineBorder(color));
			this.area= new JTextArea(20,20);
			this.area.setEditable(false);
			this.area.setText("true;");
			this.area.setCaretPosition(0);
			this.add(new JScrollPane(this.area),BorderLayout.CENTER);
			
			JPanel top=new JPanel(new FlowLayout(FlowLayout.LEADING));
			this.cboxEnable=new JCheckBox("Enable", true);
			this.cboxEnable.addActionListener(this);
			top.add(this.cboxEnable);
			this.add(top,BorderLayout.NORTH);
			
			this.colorButton=new JButton(new AbstractAction("Color")
				{
				private static final long serialVersionUID = 1L;

				@Override
				public void actionPerformed(ActionEvent arg0)
					{
					JColorChooser chooser=new JColorChooser(color);
					if(JOptionPane.showConfirmDialog(SelectorPane.this, chooser,"Choose color",JOptionPane.OK_CANCEL_OPTION,JOptionPane.PLAIN_MESSAGE,null)!=JOptionPane.OK_OPTION) return;
					color= chooser.getColor();
					colorButton.setBackground(color);
					fireChanged();
					}
				});
			this.colorButton.setContentAreaFilled(true);
			this.colorButton.setBackground(this.color);
			top.add(this.colorButton);
			
			JPanel bot=new JPanel(new FlowLayout(FlowLayout.TRAILING));
			bot.add(this.info=new JTextField(10));
			this.info.setForeground(Color.RED);
			this.info.setEnabled(false);
			this.add(bot,BorderLayout.SOUTH);
			bot.add(new JButton(new AbstractAction("Edit")
				{
				private static final long serialVersionUID = 1L;
				@Override
				public void actionPerformed(ActionEvent e)
					{
					edit();
					}
				}));
			
			}
		
		@Override
		public void actionPerformed(ActionEvent ae)
			{
			fireChanged();
			}
		
		private void edit()
			{
			JTextArea text=new JTextArea(20,20);
			text.setText(this.area.getText());
			text.setCaretPosition(0);
			JScrollPane scroll=new JScrollPane(text);
			scroll.setPreferredSize(new Dimension(500,400));
			if(JOptionPane.showConfirmDialog(this, scroll,"Edit",JOptionPane.OK_CANCEL_OPTION,JOptionPane.PLAIN_MESSAGE,null)!=JOptionPane.OK_OPTION)
				{
				return;
				}
			String script=text.getText().trim();
			if(script.length()==0) return;
			this.area.setText(script);
			this.area.setCaretPosition(0);
			fireChanged();
			}
		
		
		Selector getSelector()
			{
			if(!this.cboxEnable.isSelected()) return null;
			try
				{
				Selector s= new Selector(this.area.getText());
				s.c=color;
				this.info.setText("");
				return s;
				}
			catch(Exception err)
				{
				this.info.setText(String.valueOf(err.getMessage()));
				this.info.setCaretPosition(0);
				return null;
				}
			}
		
		
		void fireChanged()
			{
			dirty_flag=true;
			drawinArea.repaint();
			}
		}
	
	/**
	 * 
	 * Selector
	 *
	 */
	private class Selector
		{
		private Color c;
		private CompiledScript script;
		private Bindings bindings;
		
		Selector(String program) throws ScriptException
			{
			this.script=compiler.compile(program);
			this.bindings=script.getEngine().createBindings();	
			}
		
		boolean match(Fid pos,STypes reference,Genotype genotypes[])
			{
			try
				{
				this.bindings.put("chrom",pos.getChromosomeId());
				this.bindings.put("position",pos.getPosition());
				this.bindings.put("ref",reference.getMajorBase());
				this.bindings.put("repeat",reference.isRepeat());
				this.bindings.put("knownSnp",reference.isSnp());
				this.bindings.put("genotypes",genotypes);
				Object o= this.script.eval(bindings);
				if(o==null || !(o instanceof Boolean)) return false;
				return Boolean.class.cast(o).booleanValue();
				}
			catch(Exception err)
				{
				return false;
				}
			}
		}
	
	/**
	 * 
	 * DrawingThread
	 *
	 */
	private class DrawingThread
	extends Thread
		{
		BufferedImage offscreen;
		volatile long lastRepaint=System.currentTimeMillis();
		Model.ChromInfo currentChrom;
		int view_start;
		int view_length;
		List<Selector> selectors;
		int counts[][];
		int maximums[];
		STypes genotype_array[][]=null;
		int histogram_width;
		volatile boolean abort_flag=false;
		final int DEFAULT_HISTOGRAM_WIDTH=10;
		boolean firstInvokation=true;
		final int MAX_TABLE_ROWS=1000;
		private List<TableRow> rows=new ArrayList<TableRow>(MAX_TABLE_ROWS);
		private boolean should_update_table=true;
		private boolean display_base_flag=false;
		
		DrawingThread(BufferedImage offscreen,List<Selector> selectors)
			{
			this.offscreen=offscreen;
			this.currentChrom=Frame.this.currentChrom;
			this.view_start= Frame.this.view_start;
			this.view_length= Frame.this.view_length;
			this.selectors=selectors;
			
			this.histogram_width = DEFAULT_HISTOGRAM_WIDTH;
			int alt_width=(this.offscreen.getWidth()/this.view_length);
			
			if(this.histogram_width< alt_width)
				{
				this.histogram_width=alt_width;
				}
			if(this.histogram_width==0) this.histogram_width=1;
			
			
			this.counts=new int[selectors.size()][];
			this.maximums=new int[selectors.size()];
			
			int number_of_histograms=offscreen.getWidth()/this.histogram_width;
			for(int i=0;i< counts.length;++i)
				{
				this.counts[i]=new int[number_of_histograms];
				}
			
			
			if(view_length< offscreen.getWidth())
				{
				display_base_flag=true;
				this.genotype_array=new STypes[number_of_histograms][];
				}
			}
		

		public void invoke(Fid fid, STypes[] v)
			{
			final int TIME_BETWEEN_REPAINT_MILLISEC=1000;
			//int number_of_histograms=offscreen.getWidth()/this.histogram_width;
			boolean dirty=false;
			int index = (int)Math.floor(((fid.getPosition()-this.view_start)/(double)this.view_length)
					*
					(int)(offscreen.getWidth()/this.histogram_width))
					;
			
			Genotype genotypes[]=new Genotype[(v.length-1)/2];
			for(int i=1;i+1<v.length;i+=2)
				{
				genotypes[(i-1)/2]=new Genotype(v[i],v[i+1]);
				}
			
			for(int i=0;i< this.selectors.size();++i)
				{
				if(selectors.get(i).match(fid, v[0],genotypes))
					{
					if(index<0)
						{
						System.err.println(this.view_start+" "+this.view_length+" "+fid);
						}
					this.counts[i][index]++;
					this.maximums[i]=Math.max(this.maximums[i], this.counts[i][index]);
					if(display_base_flag)
						{
						this.genotype_array[index]=v;
						}
					dirty=true;
					}
				}
			
			if(dirty)
				{
				if(this.rows.size()< MAX_TABLE_ROWS)
					{
					TableRow tr= new TableRow();
					tr.fid= fid;
					tr.reference= v[0];
					tr.genotypes= genotypes;
					this.rows.add(tr);
					}
				else
					{
					this.should_update_table=false;
					}
				}
			
			if(!firstInvokation &&  !dirty) return;
			long n=System.currentTimeMillis();
			if(firstInvokation || n-lastRepaint>TIME_BETWEEN_REPAINT_MILLISEC)
				{
				this.repaint();
				lastRepaint=n;
				firstInvokation=false;
				}
			return;
			}
		
		public void run()
			{
			
			PrimaryDB<Fid, STypes[]> stypesdb=null;
			Walker<Fid,STypes[]> w=null;
			for(String path:model.getSTypes())
				{
				if(abort_flag) break;
				try
					{
					stypesdb=model.openSTypesDB(path);
					w= stypesdb.openWalker(txn);
					
					boolean first=true;
					while(!abort_flag &&
							!isInterrupted() &&
						(first?
							w.getSearchKeyRange(new Fid(ORGANISM_ID,this.currentChrom.getId(), this.view_start)):
							w.getNext()
							)==OperationStatus.SUCCESS)
						{
						first=false;
						Fid key= w.getKey();
						if( key.getChromosomeId()!=this.currentChrom.getId() ||
							key.getPosition()>= this.view_start+this.view_length) break;
						
						invoke(key, w.getValue());
						}
					this.repaint();
						
					SwingUtilities.invokeAndWait(new Runnable()
						{	
						@Override
						public void run()
							{
							progress.setIndeterminate(false);
							}
						});
					}
				catch (InterruptedException e)
					{
					//ignore e.printStackTrace();
					}
				catch (Exception e)
					{
					e.printStackTrace();
					}
				finally
					{
					if(stypesdb!=null) try { stypesdb.close(); } catch(Exception err){} 
					stypesdb=null;
					if(w!=null) try { w.close(); } catch(Exception err){} 
					w=null;
					}
				}
			}
		
		void repaint()
			{
			if(abort_flag || isInterrupted()) return;
			
			
			try
				{
				SwingUtilities.invokeAndWait(new Runnable()
					{
					@Override
					public void run()
						{
						//System.err.println("BEGIN repaint");
						Graphics2D g= offscren.createGraphics();
						GradientPaint grad= new GradientPaint(offscren.getWidth()/2, 0, Color.GRAY,offscren.getWidth()/2f, offscren.getHeight(), Color.WHITE, false);
						g.setPaint(grad);
						g.fillRect(0, 0, drawinArea.getWidth(), drawinArea.getHeight());
						float histogram_height= (offscreen.getHeight()*0.75f)/selectors.size();
						int count= offscreen.getWidth()/histogram_width;
						int step=(int)(Math.pow(10,Math.ceil(Math.log10(view_length)))/10);
						//System.err.println(step+" "+view_length);
						if(step>0)
							{
							g.setFont(new Font("Courier",Font.PLAIN,10));
							int ticks = view_start - view_start%step;
							//System.err.println("ticks:"+ticks);
							while(ticks<= view_start+view_length)
								{
								int x= (int)(((ticks-view_start)/(double)view_length)*offscreen.getWidth());
								g.setColor(Color.WHITE);
								g.drawLine(x, 0, x, offscreen.getHeight());
								g.setColor(Color.GRAY);
								g.drawLine(x+1, 0, x+1, offscreen.getHeight());
								
								
								g.translate(x,10);
								g.rotate(Math.PI/2);
								g.setColor(Color.GRAY);
								g.drawString(String.valueOf(ticks),0,-5);
								g.setColor(Color.WHITE);
								g.drawString(String.valueOf(ticks),1,-6);
								g.rotate(-Math.PI/2);
								g.translate(-x,-10);
								//
								
								ticks+=step;
								}
							}
						
						if(display_base_flag)
							{
							Font f= new Font("Courier", Font.PLAIN, DEFAULT_HISTOGRAM_WIDTH);
							g.setFont(f);
							}
						
						
						for(int i=0;i< count;++i)
							{
							
							if(display_base_flag && genotype_array[i]!=null)
								{
								g.setColor(Color.DARK_GRAY);
								g.drawString(
									String.valueOf(genotype_array[i][0].getMajorBase()),
									(i*histogram_width)+histogram_width/2-DEFAULT_HISTOGRAM_WIDTH/2,
									12);
								}
							
							int y=offscreen.getHeight()-1;
							for(int j=0;j< selectors.size();++j)
								{
								if(counts[j][i]>0)
									{
									float h= (counts[j][i]/(float)maximums[j])*(histogram_height);
									Rectangle r= new Rectangle(
										i*histogram_width,
										(int)(y-h),
										histogram_width,
										(int)h
										);
									//g.setColor(selectors.get(j).c);
									g.setPaint(new LinearGradientPaint(
											(float)r.getMinX(),
											(float)r.getCenterY(),
											(float)r.getMaxX(),
											(float)r.getCenterY(),
											new float[]{0f,0.5f,1f},
											new Color[]{selectors.get(j).c,Color.WHITE,selectors.get(j).c}
										));
									g.fill(r);
									g.setColor(Color.BLACK);
									g.draw(r);
									}
								y-=histogram_height;
								}
							
							if(display_base_flag)
								{
								
								}
							
							
							}
						
						g.dispose();
						
						if(should_update_table)
							{
							genotypeTable.rows=DrawingThread.this.rows;
							genotypeTable.fireTableDataChanged();
							}
						dirty_flag=false;
						drawinArea.repaint();
						//System.err.println("END repaint");
						}
					});
				}
			catch (InterruptedException e)
				{
				//ignore e.printStackTrace();
				}
			catch (InvocationTargetException e)
				{
				e.printStackTrace();
				}
			}
		}
	

	/**
	 * Frame
	 */
	private Frame(Model model)
		{
		super("Gtypes");
		setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
		this.model=model;
		
		this.currentChrom=model.getChromosomes().get(0);
		
		this.view_start= currentChrom.getStart();
		this.view_length=currentChrom.getDataSize();
		
		
		ScriptEngineManager manager = new ScriptEngineManager();
		ScriptEngine engine = manager.getEngineByName("js");
		if(engine==null) throw new NullPointerException("no js engine");
		this.compiler = Compilable.class.cast(engine);
		
		
		
		JPanel content= new JPanel(new BorderLayout(5,5));
		content.setBorder(new EmptyBorder(5,5,5,5));
		JPanel top= new JPanel(new FlowLayout(FlowLayout.LEADING));
		content.add(top,BorderLayout.NORTH);
		
		top.add(this.comboChromosome=new JComboBox(new Vector<Model.ChromInfo>(model.getChromosomes())));
		
		top.add(new JLabel("Start:",JLabel.RIGHT));
		top.add(txtFieldStart=new JTextField(String.valueOf(this.view_start),7));
		top.add(new JLabel("End:",JLabel.RIGHT));
		top.add(txtFieldEnd=new JTextField(String.valueOf(this.view_start+this.view_length),7));
		top.add(new JLabel("Length:",JLabel.RIGHT));
		top.add(txtFieldLength=new JTextField(String.valueOf(this.view_length),7));
		txtFieldLength.setEditable(false);
		top.add(new JButton(new AbstractAction("All")
			{
			private static final long serialVersionUID = 1L;
			@Override
			public void actionPerformed(ActionEvent ae)
				{
				setChromosomeId(currentChrom.getId());
				}
			}));
		
		JTabbedPane tabbedPane= new JTabbedPane(JTabbedPane.TOP);
		content.add(tabbedPane,BorderLayout.CENTER);
		
		JPanel browserPane= new JPanel(new BorderLayout(5,5));
		tabbedPane.addTab("Browser", browserPane);
		JPanel pane= new JPanel(new GridLayout(0, 1,5,5));
		browserPane.add(pane,BorderLayout.CENTER);
		
		
		addWindowListener(new WindowAdapter()
			{
			@Override
			public void windowClosing(WindowEvent arg0)
				{
				stopDrawingThread();
				setVisible(false);
				dispose();
				}
			@Override
			public void windowClosed(WindowEvent e)
				{
				try
					{
					Frame.this.model.close();
					}
				catch (DatabaseException e1)
					{
					e1.printStackTrace();
					}
				}
			});
		this.drawinArea= new JPanel(null,false)
			{
			private static final long serialVersionUID = 1L;
			@Override
			protected void paintComponent(Graphics g)
				{
				paintDrawingArea(Graphics2D.class.cast(g));
				}
			};
		this.drawinArea.setOpaque(true);
		this.drawinArea.setBackground(Color.WHITE);
		//this.drawinArea.setPreferredSize(new Dimension(500,500));
		
		JPanel pane2= new JPanel(new BorderLayout(5,5));
		pane.add(pane2);
		pane2.add(this.drawinArea,BorderLayout.CENTER);
	
		
		
		MouseAdapter mouse= new MouseAdapter()
			{
			@Override
			public void mousePressed(MouseEvent e)
				{
				mouseStart=new Point(e.getX(),e.getY());
				mouseCurrent=null;
				stopDrawingThread();
				}
			@Override
			public void mouseDragged(MouseEvent e)
				{
				if(mouseCurrent!=null)
					{
					Graphics2D g=(Graphics2D)drawinArea.getGraphics();
					g.setXORMode(drawinArea.getBackground());
					g.fillRect(Math.min(mouseStart.x,mouseCurrent.x), 0,Math.abs(mouseStart.x-mouseCurrent.x) , drawinArea.getHeight());
					g.fillRect(Math.min(mouseStart.x,e.getX()), 0,Math.abs(mouseStart.x-e.getX()) , drawinArea.getHeight());
					g.setPaintMode();
					g.dispose();
					
					txtFieldStart.setText(String.valueOf(pixel2base(Math.min(mouseStart.x,mouseCurrent.x))));
					txtFieldEnd.setText(String.valueOf(pixel2base(Math.max(mouseStart.x,mouseCurrent.x))));
					txtFieldLength.setText("##");
					}
				mouseCurrent=new Point(e.getX(),e.getY());
				}
			
			@Override
			public void mouseReleased(MouseEvent e)
				{
				if(mouseCurrent!=null && mouseCurrent.x!=mouseStart.x)
					{
					int start= pixel2base(Math.min(mouseStart.x,mouseCurrent.x));
					int end= pixel2base(Math.max(mouseStart.x,mouseCurrent.x));
					view_length=end-start;
					if(view_length==0) view_length=1;
					if(view_length> currentChrom.getDataSize() )
						{
						view_length= currentChrom.getDataSize();
						}
					view_start=start;
					if(view_start<currentChrom.getStart()) view_start=currentChrom.getStart();
					if(view_start+view_length>= currentChrom.getLength())
						{
						view_start=currentChrom.getStart();
						}
					txtFieldStart.setText(String.valueOf(view_start));
					txtFieldEnd.setText(String.valueOf(view_start+view_length));
					txtFieldLength.setText(String.valueOf(view_length));
					dirty_flag=true;
					}
				
				drawinArea.repaint();
				mouseStart=null;
				}
			};
		this.drawinArea.addMouseListener(mouse);
		this.drawinArea.addMouseMotionListener(mouse);
		
		JPanel pane3=new JPanel(new GridLayout(1,0,5,5));
		selectPanes=new SelectorPane[3];
		for(int i=0;i< selectPanes.length;++i)
			{
			selectPanes[i]=new SelectorPane();
			selectPanes[i].cboxEnable.setEnabled(i!=0);
			pane3.add(selectPanes[i]);
			}

		pane.add(pane3);
		
		JPanel bottom= new JPanel(new FlowLayout(FlowLayout.LEADING));
		browserPane.add(bottom,BorderLayout.SOUTH);
		bottom.add(new JLabel("Progress:",JLabel.RIGHT));
		this.progress=new JProgressBar();
		progress.setIndeterminate(false);
		progress.setPreferredSize(new Dimension(100,12));
		bottom.add(progress);
		
		JMenuBar bar= new JMenuBar();
		setJMenuBar(bar);
		JMenu menu= new JMenu("File");
		bar.add(menu);
		menu.add(new AbstractAction("Quit")
			{
			private static final long serialVersionUID = 1L;

			@Override
			public void actionPerformed(ActionEvent ae)
				{
				setVisible(false);
				dispose();
				}
			});
		
		
		this.comboChromosome.setSelectedIndex(0);
		this.comboChromosome.addActionListener(new ActionListener()
			{	
			@Override
			public void actionPerformed(ActionEvent e)
				{
				Model.ChromInfo info=Model.ChromInfo.class.cast(comboChromosome.getSelectedItem());
				if(info==null) return;
				setChromosomeId(info.getId());
				}
			});
		
		pane=new JPanel(new BorderLayout(5,5));
		tabbedPane.addTab("Table", pane);
		JTable table= new JTable(this.genotypeTable=new GenotypeTable());
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		pane.add(new JScrollPane(table),BorderLayout.CENTER);
		
		setContentPane(content);
		}
	
	private void setChromosomeId(Integer id)
		{
		stopDrawingThread();
		Model.ChromInfo info= this.model.getChromById(id);
		if(info==null) return;
		this.currentChrom=info;
		this.view_start=info.getStart();
		this.view_length=info.getDataSize();
		this.txtFieldStart.setText(String.valueOf(this.view_start));
		this.txtFieldLength.setText(String.valueOf(this.view_length));
		this.txtFieldEnd.setText(String.valueOf(this.view_start+this.view_length));
		dirty_flag=true;
		drawinArea.repaint();
		}
	
	private int pixel2base(int x)
		{
		return (int)(this.view_start+ (float)((x/(float)drawinArea.getWidth())*this.view_length));
		}
	
	
	
	private void paintDrawingArea(Graphics2D g1)
		{
		if(offscren==null
			|| offscren.getWidth()!=drawinArea.getWidth()
			|| offscren.getHeight()!=drawinArea.getHeight()
			)
			{
			this.offscren=new BufferedImage(drawinArea.getWidth(), drawinArea.getHeight(), BufferedImage.TYPE_INT_RGB);
			dirty_flag=true;
			}
		if(dirty_flag)
			{
			dirty_flag=false;
			startDrawingThread();
			}
		g1.drawImage(offscren,0,0,drawinArea);
		}
	private synchronized void stopDrawingThread()
		{
		if(runThread!=null)
			{
			
			runThread.abort_flag=true;
			try
				{
				runThread.join(100);
				runThread.interrupt();
				}
			catch (Exception e)
				{
				e.printStackTrace();
				}
			progress.setIndeterminate(false);
			runThread=null;
			
			}
		}
	private void startDrawingThread()
		{
		stopDrawingThread();
		
		progress.setIndeterminate(true);
		List<Selector> selectors= new ArrayList<Selector>(selectPanes.length);
		
		for(int i=0;i< selectPanes.length;++i)
			{
			Selector sel=selectPanes[i].getSelector();
			if(sel==null) continue;
			selectors.add(sel);
			}
		runThread=new DrawingThread(this.offscren,selectors);
		runThread.start();
		
		}
	
	
	public static void main(String[] args) {
		try
			{
			File cfgHome=null;
			int optind=0;
			while(optind< args.length)
				{
				if(args[optind].equals("-h"))
					{
					return;
					}
				else if(args[optind].equals("-cfg"))
					{
					cfgHome=new File(args[++optind]);
					}
				else if(args[optind].equals("--"))
					{
					optind++;
					break;
					}
				else if(args[optind].startsWith("-"))
					{
					System.err.println("Unknown option "+args[optind]);
					}
				else 
					{
					break;
					}
				++optind;
				}
			if(cfgHome==null)
				{
				System.err.println("config file missing");
				return;
				}
			Model model=new Model();
			model.open(cfgHome);
			
			final Frame f= new Frame(model);
			Dimension screen=Toolkit.getDefaultToolkit().getScreenSize();
			f.setBounds(50, 50, screen.width-100, screen.height-100);
			SwingUtilities.invokeLater(new Runnable()
				{
				@Override
				public void run()
						{
						f.setVisible(true);
						}
				});
			} 
		catch(Throwable err)
			{
			err.printStackTrace();
			}
		}
	}
